JRE Usage Example

The Java Runtime Environment (JRE) defines the core Java platform. The components of the JRE have been selected out of the Java Developer Kit (JDK) as the minimal set of API's to support java applications. Once a java application has been developed, the JRE may be bundled in as part of the final product. This is useful when a developer cannot rely on the java runtime being installed on the customer's machine, or when an installed runtime may be an earlier version than the one the product was developed for (and so may be incompatible). Including the JRE with a java application is the best way to ensure that your product runs as expected when installed at its final destination.

The following is an extended example of how to create, and bundle, a simple java application which runs on top of a JRE included with it. It is worthwhile to note the directory structure of JRE components. The structure of the JRE is intentionally almost identical to that of the JDK (with some files missing and a few files renamed). The intention is to allow for a simple, seamless transition from developing an application with the JDK, to deploying it with the more-lightweight JRE. Feel free to take, use and modify any part of this example, such as source code or makefiles.

For more information on the Java Runtime itself, see its README file.


Step 1: Develop an app

Developing an application requires a copy of the JDK , or some other development tool. Our example application is a simple GUI, jre.demo.HelloWorld. Here is the HelloWorld.java source. We'll refer to it a bit later. You can download the full HelloWorld example for these platforms: To invoke the example, change directories to the "bin" directory and execute:
    hello
Once your app works satisfactorily under the JDK, you're ready for step 2.


Step 2: Get the JRE

...for each platform you intend to deploy on. Get the JRE from the JRE Download Page.


Step 3: Native libraries

Should your application require native methods, you should first compile these into a shareable native library specific to you target platform/architecture. Our example program has a simple native method to illustrate the point. These Solaris and win32 Makefiles demonstrate how this compilation might be done. (Here is the source for the JNI-style native method. On win32, once you have built a .dll, it should be placed in the $(JRE_TOP)\bin directory (next to all the java runtime's dll's). On Solaris, you .so should be placed in the $(JRE_TOP)/lib/$(ARCH)/$(THREADS_TYPE) subdirectory, where $(ARCH) denotes the target architecture (e.g., for this example, the architecture is "sparc"), and $(THREADS_TYPE) is the type of threads the Solaris VM is using (for now, this must be "green_threads"). In the example programs, you'll see files called $(JRE_TOP)\bin\HelloWorld.dll on win32 and $(JRE_TOP)/lib/sparc/green_threads/HelloWorld.so on Solaris. Please make sure the names of your native libraries do not overwrite any of the JRE's native libraries.


Step 4: Build a platform-specific executable

Your application will need some kind of starting point, a simple program that is the first thing the end user executes. This program will in turn invoke the public static void main(String[] argv) method of your java class.

On Windows, if you have access to a C compiler during development, a small C program is the best way to do this. The sample program hello.c will do nicely. You can compile this with a macro defining JAVA_ARGS to be the name of your java class that defines main(String[] argv). An added benefit of using a small C program like this one on Windows is that, when compiled with -DWINMAIN, you can have a purely Windows application (that is, one that does not pop up a console when started by double-clicking on the desktop), if it is GUI-based.

On UNIX, a wrapper Korn-shell script like this can be used to invoke the java interpreter on your main class.

These Makefiles for win32 and Solaris were used to build the example programs. Both these simple wrapper programs should be located in the $(JRE_TOP)/bin directory. These wrappers look very much like the wrappers that invoke the java interpreter in the JDK. However, there's one main difference you should note:

Clobber CLASSPATH and JAVA_HOME environment variables

Both the wrappers make sure to unset the CLASSPATH and JAVA_HOME environment variables before invoking the interpreter. These variables may be convenient while doing development on top of the JDK, but they can cause trouble when your application is installed on a user's machine. The reason is simple: there might be several java applications installed on that machine. If a user has installed a Java development tool that modified their AUTOEXEC.BAT or .login script, then CLASSPATH and JAVA_HOME may point at a JDK1.0.2-based java runtime. If these environment variables are left intact when the java interpreter is invoked, then it will be pulling 1.0.2 classes. If you rely on 1.1 features, your program will fail in ugly ways. Worse, it's unlikely that the classes for your app will even be found in that CLASSPATH. Unsetting CLASSPATH and JAVA_HOME before invoking the JRE interpreter sanitizes your application against unpredictable results.

The default CLASSPATH used by the JRE is:

      $(JRE_TOP)/lib/rt.jar:$(JRE_TOP)/lib/i18n.jar:$(JRE_TOP)/lib/classes.jar:$(JRE_TOP)/lib/classes.zip:$(JRE_TOP)/classes
      
where the variable $(JRE_TOP) is defined to be the directory where the JRE is installed (it has 'bin' and 'lib' directories underneath it). rt.jar and i18n.jar are used to hold the runtime's (required) core classes and (optional) internationalization classes, so it is recommended that you store the classes specific to your application in either $(JRE_TOP)/lib/classes.jar, or else as individual class files in the $(JRE_TOP)/classes subdirectory.


Step 5: Build, test, and ship it!

Once you have built your wrapper executables, and put them in the (JRE_TOP)/bin subdirectory, your application should be ready to go. As with any software product, a final round of testing is advisable, now that your program has taken its finished form atop the JRE.


Question: How should my application find other resources, such as images, sounds and other files, when it runs on top of the JRE? Where should I store these things?

Running the JDK's interpreter, you can always find the top directory where the JDK is installed from java by:
      String javaHome = System.getProperty("java.home");
      /** This is the runtime directory path to the top of where
       * the java runtime is installed.  It has the 'bin' and 'lib'
       * directories underneath it.
       */
      
The mechanism is identical when your application is running on top of the JRE. In fact, our sample application HelloWorld.java uses this mechanism at rumtime to find the image it displays. The image is stored in the lib directory below $(JRE_TOP) (or $(JAVA_HOME), the two are equivalent):
      void loadImage() throws IOException {
	  URL imgURL;

	  String jh = System.getProperty("java.home");
	  String file = jh + File.separator+"lib"+
	      File.separator+"smooch.gif";
	  imgURL = new URL("file", "", file);
	  ....
      }      
      
As an aside, the lib subdirectory is the usual place to store and find such resources (so long as the file names don't collide with any of the files already there in the JRE).

Good luck! To submit comments or suggestions about the JRE, please send mail to the most appropriate engineering team from the list at JavaSoft email addresses.


Last modified: Thu Jun 26 13:19:05 PDT